#include <ClanLib/core.h>
#include <ClanLib/application.h>
#include <ClanLib/display.h>
#ifdef USE_SDL
	#include <ClanLib/sdl.h>
#else
	#include <ClanLib/gl.h>
#endif
#include <ClanLib/sound.h>
#include <ClanLib/vorbis.h>
#include <time.h>
#include "entity.h"
#include "level.h"
#include "particles.h"
#include "random.h"
#include "scene.h"
#include "tileset.h"
#include "viewport.h"
#include "viewportManager.h"
//#include "hatGuy.h"
#include "blockGuy.h"

class ClanGameApp: public CL_ClanApplication
{
public:

virtual void init_modules()
{

}

virtual void deinit_modules()
{ CL_SetupCore::deinit(); }

virtual int main(int, char **)
{
	CL_ConsoleWindow console("Console");
	console.redirect_stdio();

	// Initialize ClanLib base components
	CL_SetupCore::init();
	// Initialize the ClanLib display component
	CL_SetupDisplay::init();

	// Initilize the OpenGL drivers
	#ifdef USE_SDL
		CL_SetupSDL::init();
	#else
		CL_SetupGL::init();
	#endif
	
	try{
	CL_DisplayWindow window("GnomeQuest", 640, 480, false, false, 2);
	//window.set_title("DarkLogic");
	CL_GraphicContext *window_gc = window.get_gc();
	// Hook up callback that gets called when a resource is added to a resource manager:
	slots.connect(CL_ResourceManager::sig_resource_added(), this, &ClanGameApp::on_resource_added);
	CL_Slot slot_quit = window.sig_window_close().connect(this, &ClanGameApp::on_window_close);
	// Connect a keyboard handler to on_key_down()
	CL_Slot slot_input_down = (window.get_ic()->get_keyboard()).sig_key_down().connect(this, &ClanGameApp::on_input_down);
	// Connect a keyboard handler to on_key_up()
	CL_Slot slot_input_up = (window.get_ic()->get_keyboard()).sig_key_up().connect(this, &ClanGameApp::on_input_up);

	CL_ResourceManager resources("level.xml", new CL_Zip_Archive("level2.glv"), true);
	CL_ResourceManager default_resources("default.xml");
	resources.add_resources(default_resources);
	Scene scene(resources);
	//CL_Surface background("game/Background", &resources);

	//CL_Sprite sprite_hatguy_stand("game/sprites/hatGuy", &resources);
	//CL_Sprite sprite_hatguy_walk("game/sprites/hatGuy_walk", &resources);
	//CL_Sprite sprite_hatguy_jump("game/sprites/hatGuy_jump", &resources);
	//CL_Sprite sprite_hatguy_land("game/sprites/hatGuy_land", &resources);
	//CL_Sprite sprite_hatguy_attack("game/sprites/hatGuy_attack", &resources);

	attack_key = false;
	jump_key = false;
	left_key = false;
	right_key = false;

	//HatGuy hatGuy_instance(sprite_hatguy_stand, sprite_hatguy_walk, sprite_hatguy_jump, sprite_hatguy_land, sprite_hatguy_attack, attack_key, jump_key, left_key, right_key);
	//hatGuy_instance.pos = CL_Point(100, 100);
	//scene.en_manager.add(hatGuy_instance);
	CL_Pointf bg_position = CL_Pointf(100.0, 110.0);
	CL_Sprite sprite_blockguy("game/sprites/blockGuy", &resources);
	BlockGuy blockGuy_instance(sprite_blockguy, bg_position, jump_key, left_key, right_key);
	scene.en_manager.add(blockGuy_instance);

	CL_Rect world(0,0,640,480);
	CL_Rect screen(0,0,640,480);
	CL_Rect p_bounds(0,0,800,480);
	Viewport view(world, screen, &window_gc, blockGuy_instance, p_bounds);
	//view.setTarget(hatGuy_instance);
	scene.vp_manager.add(view);
	scene.pa_manager.add("game/Sky", &resources);
	scene.pa_manager.add("game/Clouds", &resources);
	scene.pa_manager.add("game/Mountains", &resources);

	// Setup //
	ParticleManager particleManager;
	Emitter emitter;

	emitter.pos.x = 512; emitter.pos.y = 192;
	emitter.angle = 0.0f; emitter.angleVar = 0.5f;
	emitter.speed = 1.5f; emitter.speedVar = 1.0f;
	emitter.acceleration = CL_Vector2(0.0f, 0.02f);

	emitter.life = 100; emitter.lifeVar = 75;

	emitter.emitsPerFrame = 5.0f; emitter.emitVar = 2.0f;
	emitter.totalParticles = 600;

	emitter.startColor.red = 1.0f; emitter.startColorVar.red = 0.0f;
	emitter.startColor.green = 0.5f; emitter.startColorVar.green = 0.5f;
	emitter.startColor.blue = 0.25f; emitter.startColorVar.blue = 0.2f;
	emitter.startColor.alpha = 1.0f; emitter.startColorVar.alpha = 0.0f;

	emitter.endColor.red = 0.0f; emitter.endColorVar.red = 0.0f;
	emitter.endColor.green = 1.0f; emitter.endColorVar.green = 0.0f;
	emitter.endColor.blue = 0.0f; emitter.endColorVar.blue = 0.0f;
	emitter.endColor.alpha = 0.0f; emitter.endColorVar.alpha = 0.0f;

	particleManager.addEmitter( emitter );		

	// Setup //

	quit = false;
	unsigned int old_time = CL_System::get_time();
	unsigned int framerate = 0;
	unsigned int frames = 0;
	long pos = std::cout.tellp();
	while(!quit){
		CL_Display::clear(CL_Color(255,255,255));
		
		scene.draw();

		// Update //
		//view.draw(background);
		//particleManager.update(view);
		// Update //

		framerate = (CL_System::get_time() - old_time);
		frames++;
		if(framerate >= 1000)
		{
		  //std::cout << "\rFramerate: " << ((frames * 1000) / framerate);
			frames = 0;
			old_time = CL_System::get_time();
		}

		CL_Display::flip();
		CL_System::keep_alive();
	}

	}
	catch(CL_Error error){
		std::cout << "Exception caught : " << error.message.c_str() << std::endl;
		console.display_close_message();

		return -1;
	}


	return 0;
}

private:
	bool quit;
	bool attack_key, jump_key, left_key, right_key;

	void on_window_close()
	{
		quit = true;
	}

	void on_input_down(const CL_InputEvent &key)
	{
		if(key.id == CL_KEY_SPACE)
		{
			attack_key = true;
		}
		else if(key.id == CL_KEY_UP)
		{
			jump_key = true;
		}
		else if(key.id == CL_KEY_LEFT)
		{
			left_key = true;
		}
		else if(key.id == CL_KEY_RIGHT)
		{
			right_key = true;
		}
	}

	void on_input_up(const CL_InputEvent &key)
	{
		if(key.id == CL_KEY_ESCAPE)
		{
			quit = true;
		}
		else if(key.id == CL_KEY_SPACE)
		{
			attack_key = false;
		}
		else if(key.id == CL_KEY_UP)
		{
			jump_key = false;
		}
		else if(key.id == CL_KEY_LEFT)
		{
			left_key = false;
		}
		else if(key.id == CL_KEY_RIGHT)
		{
			right_key = false;
		}
	}

	void on_resource_added(CL_Resource &resource)
	{
		// Here we check if the resource type is interesting for us.
		// We can attach any number of CL_ResourceData objects to a resource,
		// including those that clanlib also handles. They can then later
		// be retrieved with a call to CL_Resource::get_data(name_they_were_attached_with).

		std::string type = resource.get_type();

		if (type == "level")
		{
			resource.attach_data("level_data", new LevelResourceData(resource));
		}
		else if (type == "parralax")
		{
			resource.attach_data("parralax_data", new ParralaxResourceData(resource));
		}
	}
	
	// Container object for signal->slot connections.
	CL_SlotContainer slots;
} app;
